import {
  CanvasTexture,
  ClampToEdgeWrapping,
  LinearFilter,
  Object3D,
  Sprite,
  SpriteMaterial,
  Vector2,
  LinearMipmapLinearFilter
} from 'three'
import { App } from '../../application'
import Const from '../../application/constants/Const'
import AdjustHeight from './utils/AdjustHeight'
// GUI库已移除，改用接口控制

/**
 * POI配置接口 - 让类型更清晰 bro!
 */
export interface PoiConfig {
  /** 图片URL */
  url?: string
  /** POI位置 */
  position?: any
  /** 标注名称 */
  name?: string
  /** 字体大小 */
  size?: number
  /** 图片尺寸 */
  baseImageSize?: number
  /** 是否显示文字 */
  showText?: boolean
  /** 字体颜色 */
  textStyle?: string
  /** 背景色 */
  backGroundStyle?: string
  /** 背景形状样式 */
  backgroundShape?: 'circle' | 'rectangle'
  /** 背景大小倍数 (0.5-3.0) */
  backgroundSize?: number
  /** 描边颜色 */
  strokeStyle?: string
  /** 描边宽度 */
  strokeWidth?: number
  /** 是否加粗 */
  isBold?: boolean
  /** 是否斜体 */
  isItalic?: boolean
  /** 字体 */
  textfont?: string
  /** 文字对齐方式 */
  textAlign?: CanvasTextAlign
  /** 文字基线 */
  textBaseline?: CanvasTextBaseline
  /** 锚点 */
  center?: [number, number]
  /** 深度检测 */
  depthTest?: boolean
  /** 文字位置偏移X */
  textOffsetX?: number
  /** 文字位置偏移Y */
  textOffsetY?: number
  /** 是否启用GUI控制 */
  enableGUI?: boolean
  /** 文字相对矩形的位置 */
  textPosition?:
    | 'top'
    | 'bottom'
    | 'left'
    | 'right'
    | 'center'
    | 'image-only'
    | 'text-only'
  /** 默认形状类型（当图片加载失败时显示） */
  defaultShape?: 'circle' | 'rectangle' | 'triangle' | 'square'
  /** 形状大小倍数 (0.5-3.0) */
  shapeSize?: number
  /** 形状填充颜色 */
  shapeColor?: string
  /** 形状描边颜色 */
  shapeStrokeColor?: string
  /** 形状描边宽度 (0-10) */
  shapeStrokeWidth?: number
  /** 纹理图片 */
  textureImage?: HTMLImageElement | null
  /** 该poi根据falldownSurface自动调整高度*/
  falldownSurface?: Object3D
}

/**
 * POI构建器 - 使用链式调用方式创建POI
 */
export class PoiBuilder {
  private config: PoiConfig = {}

  /**
   * 设置POI名称
   * @param name POI名称
   */
  public withName(name: string): PoiBuilder {
    this.config.name = name
    return this
  }

  /**
   * 设置POI图片URL
   * @param url 图片URL
   */
  public withUrl(url: string): PoiBuilder {
    this.config.url = url
    return this
  }

  /**
   * 设置POI位置
   * @param position 位置对象
   */
  public withPosition(position: any): PoiBuilder {
    this.config.position = position
    return this
  }

  /**
   * 设置字体大小
   * @param size 字体大小
   */
  public withSize(size: number): PoiBuilder {
    this.config.size = size
    return this
  }

  /**
   * 设置图片尺寸
   * @param size 图片尺寸
   */
  public withImageSize(size: number): PoiBuilder {
    this.config.baseImageSize = size
    return this
  }

  /**
   * 设置是否显示文字
   * @param show 是否显示
   */
  public withShowText(show: boolean): PoiBuilder {
    this.config.showText = show
    return this
  }

  /**
   * 设置文字样式
   * @param color 文字颜色
   * @param isBold 是否加粗
   * @param isItalic 是否斜体
   */
  public withTextStyle(color: string, isBold?: boolean, isItalic?: boolean): PoiBuilder {
    this.config.textStyle = color
    if (isBold !== undefined) this.config.isBold = isBold
    if (isItalic !== undefined) this.config.isItalic = isItalic
    return this
  }

  /**
   * 设置文字描边
   * @param color 描边颜色
   * @param width 描边宽度
   */
  public withTextStroke(color: string, width: number): PoiBuilder {
    this.config.strokeStyle = color
    this.config.strokeWidth = width
    return this
  }

  /**
   * 设置文字字体
   * @param font 字体
   */
  public withFont(font: string): PoiBuilder {
    this.config.textfont = font
    return this
  }

  /**
   * 设置文字对齐方式
   * @param align 对齐方式
   * @param baseline 基线
   */
  public withTextAlign(align: CanvasTextAlign, baseline?: CanvasTextBaseline): PoiBuilder {
    this.config.textAlign = align
    if (baseline) this.config.textBaseline = baseline
    return this
  }

  /**
   * 设置锚点
   * @param x X轴锚点 (0-1)
   * @param y Y轴锚点 (0-1)
   */
  public withCenter(x: number, y: number): PoiBuilder {
    this.config.center = [x, y]
    return this
  }

  /**
   * 设置深度检测
   * @param enable 是否启用
   */
  public withDepthTest(enable: boolean): PoiBuilder {
    this.config.depthTest = enable
    return this
  }

  /**
   * 设置文字偏移
   * @param x X轴偏移
   * @param y Y轴偏移
   */
  public withTextOffset(x: number, y?: number): PoiBuilder {
    this.config.textOffsetX = x
    if (y !== undefined) this.config.textOffsetY = y
    return this
  }

  /**
   * 设置文字位置
   * @param position 位置
   */
  public withTextPosition(position: 'top' | 'bottom' | 'left' | 'right' | 'center' | 'image-only' | 'text-only'): PoiBuilder {
    this.config.textPosition = position
    return this
  }

  /**
   * 设置背景样式
   * @param color 背景颜色
   * @param shape 背景形状
   * @param size 背景大小倍数
   */
  public withBackground(color: string, shape?: 'circle' | 'rectangle', size?: number): PoiBuilder {
    this.config.backGroundStyle = color
    if (shape) this.config.backgroundShape = shape
    if (size) this.config.backgroundSize = size
    return this
  }

  /**
   * 设置默认形状
   * @param shape 形状类型
   * @param color 填充颜色
   * @param strokeColor 描边颜色
   * @param strokeWidth 描边宽度
   */
  public withDefaultShape(shape: 'circle' | 'rectangle' | 'triangle' | 'square', color?: string, strokeColor?: string, strokeWidth?: number): PoiBuilder {
    this.config.defaultShape = shape
    if (color) this.config.shapeColor = color
    if (strokeColor) this.config.shapeStrokeColor = strokeColor
    if (strokeWidth !== undefined) this.config.shapeStrokeWidth = strokeWidth
    return this
  }

  /**
   * 设置形状大小
   * @param size 大小倍数
   */
  public withShapeSize(size: number): PoiBuilder {
    this.config.shapeSize = size
    return this
  }

  /**
   * 设置纹理图片
   * @param image 图片对象
   */
  public withTextureImage(image: HTMLImageElement): PoiBuilder {
    this.config.textureImage = image
    return this
  }

  /**
   * 设置自动调整高度的表面
   * @param surface 表面对象
   */
  public withFalldownSurface(surface: Object3D): PoiBuilder {
    this.config.falldownSurface = surface
    return this
  }

  /**
   * 构建POI实例
   * @returns 新的POI实例
   */
  public build(): Poi2 {
    return new Poi2(this.config)
  }
}

/**
 * 文字样式配置
 */
interface TextStyle {
  color: string
  size: number
  font: string
  isBold: boolean
  isItalic: boolean
  strokeColor: string
  strokeWidth: number
  align: CanvasTextAlign
  baseline: CanvasTextBaseline
}

/**
 * 二维POI图标- 重构版本
 */
export default class Poi2 extends Sprite {
  /**
   * 静态构建器 - 创建一个POI构建器实例
   * @returns POI构建器
   */
  public static create(): PoiBuilder {
    return new PoiBuilder()
  }
  
  /**
   * 快速创建POI - 使用部分配置快速创建POI实例
   * @param name POI名称
   * @param url 图片URL
   * @param position 位置
   * @param extraConfig 额外配置
   * @returns POI实例
   */
  public static quickCreate(name: string, url?: string, position?: any, extraConfig: Partial<PoiConfig> = {}): Poi2 {
    const config: PoiConfig = {
      name,
      ...extraConfig
    }
    
    if (url) config.url = url
    if (position) config.position = position
    
    return new Poi2(config)
  }
  private app: App
  private image: HTMLImageElement | null = null
  private config: Required<PoiConfig>
  private isImageLoaded: boolean = false
  // GUI相关属性已移除，现在使用接口控制

  // 默认配置
  private static readonly DEFAULT_CONFIG: Required<PoiConfig> = {
    url: '',
    position: null,
    name: '默认点',
    size: 1000,
    baseImageSize: 1200,
    showText: true,
    textStyle: 'white',
    backGroundStyle: '',
    backgroundShape: 'rectangle',
    backgroundSize: 1.0,
    strokeStyle: 'black',
    strokeWidth: 5,
    isBold: false,
    isItalic: false,
    textfont: 'sans-serif',
    textAlign: 'center',
    textBaseline: 'middle',
    center: [0.5, 0.5],
    depthTest: true,
    textOffsetX: 0,
    textOffsetY: 0,
    enableGUI: false,
    textPosition: 'top',
    defaultShape: 'circle',
    shapeSize: 1.0,
    shapeColor: '#000000',
    shapeStrokeColor: '#000000',
    shapeStrokeWidth: 2,
    textureImage: null,
    falldownSurface: null
  }

  private adjustHeightUtil: AdjustHeight

  /**
 * 构造函数 - 增强版，支持多种配置方式
 * 
 * @example
 * // 基本用法 - 传入配置对象
 * const poi = new Poi2({ name: 'poi点1', textOffsetX: -10 })
 * 
 * // 链式调用 - 使用静态构建器
 * const poi = Poi2.create()
 *   .withName('poi点1')
 *   .withTextOffset(-10, 0)
 *   .withTextStyle('red', true, false)
 *   .build()
 */
constructor(config: PoiConfig = {}) {
  super(null)

  this.app = App.getInstance()
  this.config = { ...Poi2.DEFAULT_CONFIG, ...config }

  this.initializeSprite()
  this.initializePosition()
  this.setupAnchor()
  this.setRenderOrder()

  // 先创建一个基础材质，避免 null 错误
  this.createBasicMaterial()

  // 然后异步加载图片
  this.loadImageAndUpdate()

  this.setFalldown() //根据falldownSurface自动调整该poi的高度
}

  /**
   * 初始化基础 Sprite 属性
   */
  private initializeSprite(): void {
    // 确保 visible 属性被正确初始化
    this.visible = true
    this.matrixAutoUpdate = true
  }

  /**
   * 初始化位置
   */
  private initializePosition(): void {
    if (this.config.position) {
      const pos = this.config.position.toEPSGWeb()
      this.position.set(pos.x, pos.y, pos.z)
    }
  }

  /**
   * 设置锚点
   */
  private setupAnchor(): void {
    this.center = new Vector2(this.config.center[0], this.config.center[1])
  }

  /**
   * 设置渲染顺序
   */
  private setRenderOrder(): void {
    this.renderOrder = Infinity
  }

  /**
   * 创建基础材质 - 防止 null 错误
   */
  private createBasicMaterial(): void {
    // 创建一个 1x1 的透明 canvas 作为默认纹理
    const canvas = document.createElement('canvas')
    canvas.width = 1
    canvas.height = 1
    const ctx = canvas.getContext('2d')!
    ctx.fillStyle = 'transparent'
    ctx.fillRect(0, 0, 1, 1)

    const texture = new CanvasTexture(canvas)
    texture.minFilter = LinearFilter
    texture.wrapS = ClampToEdgeWrapping
    texture.wrapT = ClampToEdgeWrapping

    this.material = new SpriteMaterial({
      map: texture,
      transparent: true,
      depthTest: this.config.depthTest,
      opacity: 0 // 开始时不可见
    })

    // 设置基础缩放
    const labelBaseScale = 0.1
    this.scale.set(
      this.config.baseImageSize * labelBaseScale,
      this.config.baseImageSize * labelBaseScale,
      1
    )

    this.rotateX(Math.PI / 2)
  }

  /**
   * 异步加载图片并更新材质
   */
  private async loadImageAndUpdate(): Promise<void> {
    if (this.config.url) {
      try {
        this.image = await this.loadImageAsync(this.config.url)
        this.isImageLoaded = true
      } catch (error) {
        console.warn('POI image loading failed:', error)
        this.isImageLoaded = false
      }
    }

    // 无论图片是否加载成功，都创建最终材质
    this.createFinalMaterial()
  }

  /**
   * 异步加载图片
   */
  private loadImageAsync(url: string): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const img = new Image()
      img.setAttribute('crossOrigin', 'anonymous')
      img.onload = () => resolve(img)
      img.onerror = () => reject(new Error(`Failed to load image: ${url}`))
      img.src = url
    })
  }

  /**
   * 创建最终材质
   */
  private createFinalMaterial(): void {
    const canvas = this.createCanvas()
    const texture = this.createTexture(canvas)

    // 安全地处理材质更新
    if (this.material) {
      const oldMaterial = this.material as SpriteMaterial
      if (oldMaterial.map) {
        oldMaterial.map.dispose()
      }
      oldMaterial.dispose()
    }

    this.material = new SpriteMaterial({
      map: texture,
      transparent: true,
      depthTest: this.config.depthTest,
      opacity: 1 // 现在可见
    })

    this.applyScale(canvas)
  }

  /**
   * 创建Canvas
   */
  private createCanvas(): HTMLCanvasElement {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')!

    const dimensions = this.calculateCanvasDimensions(ctx)
    canvas.width = dimensions.width
    canvas.height = dimensions.height

    // 填充透明背景
    ctx.clearRect(0, 0, canvas.width, canvas.height)

    this.drawContent(ctx, dimensions)

    return canvas
  }

  /**
   * 计算Canvas尺寸
   */
  private calculateCanvasDimensions(ctx: CanvasRenderingContext2D): {
    width: number
    height: number
  } {
    // 仅图片模式
    if (this.config.textPosition === 'image-only') {
      return {
        width: this.config.baseImageSize,
        height: this.config.baseImageSize
      }
    }

    // 仅文字模式
    if (this.config.textPosition === 'text-only') {
      if (!this.config.showText || !this.config.name) {
        // 如果没有文字，返回最小尺寸
        return { width: 100, height: 100 }
      }
      const textStyle = this.getTextStyle()
      ctx.font = this.buildFontString(textStyle)
      const textWidth = ctx.measureText(this.config.name).width
      const borderSize = 5
      const doubleBorderSize = borderSize * 2
      const textHeight = this.config.size + doubleBorderSize

      return {
        width: textWidth + doubleBorderSize,
        height: textHeight
      }
    }

    // 如果没有文字，只显示图片
    if (!this.config.showText || !this.config.name) {
      return {
        width: this.config.baseImageSize,
        height: this.config.baseImageSize
      }
    }

    const textStyle = this.getTextStyle()
    ctx.font = this.buildFontString(textStyle)
    const textWidth = ctx.measureText(this.config.name).width

    const borderSize = 5
    const doubleBorderSize = borderSize * 2
    const textHeight = this.config.size + doubleBorderSize

    // 根据文字位置计算不同的canvas尺寸
    switch (this.config.textPosition) {
      case 'top':
      case 'bottom':
        return {
          width: Math.max(
            textWidth + doubleBorderSize,
            this.config.baseImageSize
          ),
          height: textHeight + this.config.baseImageSize
        }

      case 'left':
      case 'right':
        return {
          width: textWidth + doubleBorderSize + this.config.baseImageSize,
          height: Math.max(textHeight, this.config.baseImageSize)
        }

      case 'center':
      default:
        return {
          width: Math.max(
            textWidth + doubleBorderSize,
            this.config.baseImageSize
          ),
          height: Math.max(textHeight, this.config.baseImageSize)
        }
    }
  }

  /**
   * 获取文字样式配置
   */
  private getTextStyle(): TextStyle {
    return {
      color: this.config.textStyle,
      size: this.config.size,
      font: this.config.textfont,
      isBold: this.config.isBold,
      isItalic: this.config.isItalic,
      strokeColor: this.config.strokeStyle,
      strokeWidth: this.config.strokeWidth,
      align: this.config.textAlign,
      baseline: this.config.textBaseline
    }
  }

  /**
   * 构建字体字符串
   */
  private buildFontString(style: TextStyle): string {
    const bold = style.isBold ? 'bold ' : ''
    const italic = style.isItalic ? 'italic ' : ''
    return `${bold}${italic}${style.size}px ${style.font}`
  }

  /**
   * 计算文字绘制位置
   */
  private calculateTextPosition(
    dimensions: { width: number; height: number },
    doubleBorderSize: number
  ): { x: number; y: number } {
    const textHeight = this.config.size + doubleBorderSize
    const imageSize = this.config.baseImageSize

    switch (this.config.textPosition) {
      case 'top':
        return {
          x: dimensions.width / 2,
          y: textHeight / 2
        }

      case 'bottom':
        return {
          x: dimensions.width / 2,
          y: imageSize + textHeight / 2
        }

      case 'left':
        return {
          x: (dimensions.width - imageSize) / 2,
          y: dimensions.height / 2
        }

      case 'right':
        return {
          x: imageSize + (dimensions.width - imageSize) / 2,
          y: dimensions.height / 2
        }

      case 'text-only':
        // 仅文字模式
        return {
          x: dimensions.width / 2,
          y: dimensions.height / 2
        }

      case 'center':
      default:
        return {
          x: dimensions.width / 2,
          y: dimensions.height / 2
        }
    }
  }

  /**
   * 绘制内容到Canvas
   */
  private drawContent(
    ctx: CanvasRenderingContext2D,
    dimensions: { width: number; height: number }
  ): void {
    const borderSize = 5
    const doubleBorderSize = borderSize * 2

    // 仅图片模式
    if (this.config.textPosition === 'image-only') {
      if (this.isImageLoaded && this.image) {
        this.drawImage(ctx, dimensions, doubleBorderSize)
      } else {
        this.drawDefaultShape(ctx, dimensions, doubleBorderSize)
      }
      return
    }

    // 仅文字模式
    if (this.config.textPosition === 'text-only') {
      if (this.config.showText && this.config.name) {
        this.drawText(ctx, dimensions, borderSize, doubleBorderSize)
      }
      return
    }

    // 混合模式 - 绘制文字和图片
    // 绘制文字部分
    if (this.config.showText && this.config.name) {
      this.drawText(ctx, dimensions, borderSize, doubleBorderSize)
    }

    // 绘制图片部分
    if (this.isImageLoaded && this.image) {
      this.drawImage(ctx, dimensions, doubleBorderSize)
    } else {
      // 如果没有图片，绘制一个默认矩形
      this.drawDefaultShape(ctx, dimensions, doubleBorderSize)
    }
  }

  /**
   * 绘制文字
   */
  private drawText(
    ctx: CanvasRenderingContext2D,
    dimensions: { width: number; height: number },
    borderSize: number,
    doubleBorderSize: number
  ): void {
    const textStyle = this.getTextStyle()

    // 设置字体
    ctx.font = this.buildFontString(textStyle)
    ctx.textAlign = textStyle.align
    ctx.textBaseline = textStyle.baseline

    // 根据文字位置计算坐标
    const textPos = this.calculateTextPosition(dimensions, doubleBorderSize)
    const textX = textPos.x + this.config.textOffsetX
    const textY = textPos.y + this.config.textOffsetY

    // 绘制跟随文字移动的背景框
    if (this.config.backGroundStyle) {
      this.drawTextBackground(ctx, textX, textY, borderSize, doubleBorderSize)
    }

    // 绘制文字描边和填充
    this.drawTextWithStroke(ctx, this.config.name, textX, textY, textStyle)
  }

  /**
   * 绘制跟随文字的动态背景框（支持圆形或矩形，带内边距，文字垂直居中）
   */
  private drawTextBackground(
    ctx: CanvasRenderingContext2D,
    textX: number,
    textY: number,
    borderSize: number,
    doubleBorderSize: number
  ): void {
    // 测量文字实际尺寸
    const textMetrics = ctx.measureText(this.config.name)
    const textWidth = textMetrics.width
    const textHeight = this.config.size

    // 文字和背景框之间的内边距（四周均匀）
    const padding = Math.max(textHeight * 0.1, 15) // 内边距：文字高度的10%，最小15像素

    // 计算文字的实际高度（包括上下延伸部分）
    // 注意：Canvas中文字基线在文字底部，需要调整垂直位置使文字居中
    const fontAscent = textMetrics.actualBoundingBoxAscent || textHeight * 0.7 // 基线以上高度
    const fontDescent = textMetrics.actualBoundingBoxDescent || textHeight * 0.3 // 基线以下高度
    const actualTextHeight = fontAscent + fontDescent

    // 计算背景框的基础位置和尺寸（加上内边距）
    let bgWidth = textWidth + padding * 2 // 左右各加padding
    let bgHeight = actualTextHeight + padding * 2 // 上下各加padding

    // 应用背景大小倍数
    const sizeMultiplier = this.config.backgroundSize || 1.0
    bgWidth *= sizeMultiplier
    bgHeight *= sizeMultiplier

    const bgX = textX - bgWidth / 2

    // 调整垂直位置，使文字在背景框中真正居中
    // 文字基线位置需要考虑字体上下延伸的不对称性
    const bgY = textY - fontAscent - padding * sizeMultiplier

    // 设置填充样式
    ctx.fillStyle = this.config.backGroundStyle

    // 根据背景形状样式绘制不同的背景
    if (this.config.backgroundShape === 'circle') {
      // 绘制圆形背景
      const radius = Math.max(bgWidth, bgHeight) / 2
      const centerX = bgX + bgWidth / 2
      const centerY = bgY + bgHeight / 2

      ctx.beginPath()
      ctx.arc(centerX, centerY, radius, 0, Math.PI * 2)
      ctx.fill()
    } else {
      // 默认绘制圆角矩形背景
      const cornerRadius = Math.min(bgHeight / 0.5, 30)
      this.roundRect(ctx, bgX, bgY, bgWidth, bgHeight, cornerRadius)
      ctx.fill()
    }
  }

  /**
   * 绘制圆角矩形路径
   */
  private roundRect(
    ctx: CanvasRenderingContext2D,
    x: number,
    y: number,
    width: number,
    height: number,
    radius: number
  ): void {
    ctx.beginPath()
    ctx.moveTo(x + radius, y)
    ctx.lineTo(x + width - radius, y)
    ctx.arcTo(x + width, y, x + width, y + radius, radius)
    ctx.lineTo(x + width, y + height - radius)
    ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
    ctx.lineTo(x + radius, y + height)
    ctx.arcTo(x, y + height, x, y + height - radius, radius)
    ctx.lineTo(x, y + radius)
    ctx.arcTo(x, y, x + radius, y, radius)
    ctx.closePath()
  }

  /**
   * 绘制带描边的文字
   */
  private drawTextWithStroke(
    ctx: CanvasRenderingContext2D,
    text: string,
    x: number,
    y: number,
    style: TextStyle
  ): void {
    // 设置阴影效果作为描边
    ctx.shadowColor = style.strokeColor
    ctx.shadowBlur = style.strokeWidth
    ctx.shadowOffsetX = style.strokeWidth
    ctx.shadowOffsetY = style.strokeWidth

    // 绘制描边
    ctx.strokeStyle = style.strokeColor
    ctx.strokeText(text, x, y)

    // 绘制文字填充
    ctx.fillStyle = style.color
    ctx.fillText(text, x, y)

    // 清除阴影
    ctx.shadowColor = 'transparent'
    ctx.shadowBlur = 0
    ctx.shadowOffsetX = 0
    ctx.shadowOffsetY = 0
  }

  /**
   * 绘制图片
   */
  private drawImage(
    ctx: CanvasRenderingContext2D,
    dimensions: { width: number; height: number },
    doubleBorderSize: number
  ): void {
    if (!this.image) return

    const imagePos = this.calculateImagePosition(dimensions, doubleBorderSize)

    ctx.drawImage(
      this.image,
      imagePos.x,
      imagePos.y,
      this.config.baseImageSize,
      this.config.baseImageSize
    )
  }

  /**
   * 计算图片绘制位置
   */
  private calculateImagePosition(
    dimensions: { width: number; height: number },
    doubleBorderSize: number
  ): { x: number; y: number } {
    const textHeight = this.config.size + doubleBorderSize
    const imageSize = this.config.baseImageSize

    // 仅图片模式
    if (this.config.textPosition === 'image-only') {
      return {
        x: (dimensions.width - imageSize) / 2,
        y: (dimensions.height - imageSize) / 2
      }
    }

    if (!this.config.showText || !this.config.name) {
      return {
        x: (dimensions.width - imageSize) / 2,
        y: (dimensions.height - imageSize) / 2
      }
    }

    switch (this.config.textPosition) {
      case 'top':
        return {
          x: (dimensions.width - imageSize) / 2,
          y: textHeight
        }

      case 'bottom':
        return {
          x: (dimensions.width - imageSize) / 2,
          y: 0
        }

      case 'left':
        return {
          x: dimensions.width - imageSize,
          y: (dimensions.height - imageSize) / 2
        }

      case 'right':
        return {
          x: 0,
          y: (dimensions.height - imageSize) / 2
        }

      case 'center':
      default:
        return {
          x: (dimensions.width - imageSize) / 2,
          y: (dimensions.height - imageSize) / 2
        }
    }
  }

  /**
   * 绘制默认形状（当没有图片时）
   */
  private drawDefaultShape(
    ctx: CanvasRenderingContext2D,
    dimensions: { width: number; height: number },
    doubleBorderSize: number
  ): void {
    const shapePos = this.calculateImagePosition(dimensions, doubleBorderSize)
    const centerX = shapePos.x + this.config.baseImageSize / 2
    const centerY = shapePos.y + this.config.baseImageSize / 2
    const baseSize = this.config.baseImageSize / 2
    const size = baseSize * this.config.shapeSize

    // 使用独立的形状颜色和描边设置
    ctx.fillStyle = this.config.shapeColor
    ctx.strokeStyle = this.config.shapeStrokeColor
    ctx.lineWidth = this.config.shapeStrokeWidth

    // 绘制形状
    this.drawShapeWithTexture(ctx, centerX, centerY, size)
  }

  /**
   * 绘制带纹理的形状
   */
  private drawShapeWithTexture(
    ctx: CanvasRenderingContext2D,
    centerX: number,
    centerY: number,
    size: number
  ): void {
    // 第一步：绘制形状背景
    this.drawShapeBackground(ctx, centerX, centerY, size)

    // 第二步：如果有纹理图片，居中绘制（保持原尺寸）
    if (this.config.textureImage) {
      this.drawCenteredTexture(ctx, centerX, centerY, size)
    }
  }

  /**
   * 绘制形状背景（现在设为透明，只显示图片）
   */
  private drawShapeBackground(
    ctx: CanvasRenderingContext2D,
    centerX: number,
    centerY: number,
    size: number
  ): void {
    // 背景透明化 - 只有在没有纹理图片时才显示形状背景
    if (!this.config.textureImage) {
      // 设置形状样式
      ctx.fillStyle = this.config.shapeColor
      ctx.strokeStyle = this.config.shapeStrokeColor
      ctx.lineWidth = this.config.shapeStrokeWidth

      // 创建形状路径
      this.createShapePath(ctx, centerX, centerY, size)

      // 填充形状背景
      ctx.fill()

      // 绘制描边
      if (this.config.shapeStrokeWidth > 0) {
        ctx.stroke()
      }
    }
    // 如果有纹理图片，背景完全透明，不绘制任何形状
  }

  /**
   * 创建形状路径（用于背景绘制）
   */
  private createShapePath(
    ctx: CanvasRenderingContext2D,
    centerX: number,
    centerY: number,
    size: number
  ): void {
    ctx.beginPath()

    switch (this.config.defaultShape) {
      case 'circle':
        ctx.arc(centerX, centerY, size / 2, 0, Math.PI * 2)
        break

      case 'rectangle':
        const rectWidth = size * 0.8
        const rectHeight = size * 0.6
        ctx.rect(
          centerX - rectWidth / 2,
          centerY - rectHeight / 2,
          rectWidth,
          rectHeight
        )
        break

      case 'square':
        const squareSize = size * 0.7
        ctx.rect(
          centerX - squareSize / 2,
          centerY - squareSize / 2,
          squareSize,
          squareSize
        )
        break

      case 'triangle':
        const triangleSize = size * 0.8
        ctx.moveTo(centerX, centerY - triangleSize / 2) // 顶点
        ctx.lineTo(centerX - triangleSize / 2, centerY + triangleSize / 2) // 左下
        ctx.lineTo(centerX + triangleSize / 2, centerY + triangleSize / 2) // 右下
        ctx.closePath()
        break

      default:
        ctx.arc(centerX, centerY, size / 2, 0, Math.PI * 2)
        break
    }
  }

  /**
   * 绘制居中的纹理图片（保持原尺寸）
   */
  private drawCenteredTexture(
    ctx: CanvasRenderingContext2D,
    centerX: number,
    centerY: number,
    shapeSize: number
  ): void {
    if (!this.config.textureImage) return

    const img = this.config.textureImage

    // 计算图片的适配尺寸（保持宽高比，大小随形状变化）
    const maxSize = shapeSize * 0.8 // 图片尺寸为形状大小的80%
    const adaptedSize = this.calculateAdaptedImageSize(img, maxSize)

    // 计算居中位置
    const drawX = centerX - adaptedSize.width / 2
    const drawY = centerY - adaptedSize.height / 2

    try {
      // 绘制居中的图片（保持宽高比）
      ctx.drawImage(img, drawX, drawY, adaptedSize.width, adaptedSize.height)
    } catch (error) {
      console.warn('绘制居中纹理图片失败:', error)
    }
  }

  /**
   * 计算图片适配尺寸（保持宽高比）
   * 修改：始终随着形状大小变化，不再限制为原始尺寸
   */
  private calculateAdaptedImageSize(
    img: HTMLImageElement,
    maxSize: number
  ): { width: number; height: number } {
    const imgWidth = img.naturalWidth || img.width
    const imgHeight = img.naturalHeight || img.height

    // 计算宽高比
    const aspectRatio = imgWidth / imgHeight

    // 计算缩放后的尺寸（始终使用maxSize的80%作为限制）
    let newWidth, newHeight

    if (aspectRatio >= 1) {
      // 宽图
      newWidth = maxSize
      newHeight = maxSize / aspectRatio
    } else {
      // 高图
      newHeight = maxSize
      newWidth = maxSize * aspectRatio
    }

    return {
      width: newWidth,
      height: newHeight
    }
  }

  /**
   * 创建纹理
   */
  private createTexture(canvas: HTMLCanvasElement): CanvasTexture {
    const texture = new CanvasTexture(canvas)
    texture.minFilter = LinearMipmapLinearFilter
    texture.wrapS = ClampToEdgeWrapping
    texture.wrapT = ClampToEdgeWrapping
    texture.generateMipmaps = true
    texture.anisotropy = 8
    texture.colorSpace = 'srgb'; 
    return texture
  }

  /**
   * 应用缩放f
   */
  private applyScale(canvas: HTMLCanvasElement): void {
    const labelBaseScale = 0.1
    this.scale.x = canvas.width * labelBaseScale
    this.scale.y = canvas.height * labelBaseScale

    // 保存原始缩放值
    this.userData.originScaleX = this.scale.x
    this.userData.originScaleY = this.scale.y

    // 应用自定义缩放
    if (this.userData.modelScaleX) this.scale.x *= this.userData.modelScaleX
    if (this.userData.modelScaleY) this.scale.y *= this.userData.modelScaleY
  }

  /**
   * 应用旋转
   */
  private applyRotation(): void {
    this.rotateX(Math.PI / 2)
  }

  // =========================
  // 新接口控制系统
  // =========================

  /**
   * 接口1: 文本内容和样式控制
   * @param config 文本配置对象
   * @returns 当前POI实例，支持链式调用
   */
  public updateTextContentAndStyle(config: {
    name?: string // 文字内容
    size?: number // 字体大小 (10-100)
    strokeWidth?: number // 描边宽度 (0-20)
    textStyle?: string // 字体颜色
    strokeStyle?: string // 描边颜色
    isBold?: boolean // 是否加粗
    isItalic?: boolean // 是否斜体
    textfont?: string // 字体类型
  }): Poi2 {
    // 更新配置
    if (config.name !== undefined) this.config.name = config.name
    if (config.size !== undefined)
      this.config.size = Math.max(10, Math.min(1000, config.size))
    if (config.strokeWidth !== undefined)
      this.config.strokeWidth = Math.max(0, Math.min(20, config.strokeWidth))
    if (config.textStyle !== undefined) this.config.textStyle = config.textStyle
    if (config.strokeStyle !== undefined)
      this.config.strokeStyle = config.strokeStyle
    if (config.isBold !== undefined) this.config.isBold = config.isBold
    if (config.isItalic !== undefined) this.config.isItalic = config.isItalic
    if (config.textfont !== undefined) this.config.textfont = config.textfont

    // 重新渲染
    this.createFinalMaterial()
    return this
  }

  /**
   * 接口2: 文本布局控制
   * @param textPosition 文字相对图片的位置，或仅显示模式
   * @returns 当前POI实例，支持链式调用
   */
  public updateTextLayout(
    textPosition:
      | 'top'
      | 'bottom'
      | 'left'
      | 'right'
      | 'center'
      | 'image-only'
      | 'text-only'
  ): Poi2 {
    this.config.textPosition = textPosition
    this.createFinalMaterial()
    return this
  }

  /**
   * 接口3: 位置微调控制
   * @param config 位置配置对象
   * @returns 当前POI实例，支持链式调用
   */
  public updateTextOffset(config: {
    textOffsetX?: number // X轴偏移 (-200 到 200)
    textOffsetY?: number // Y轴偏移 (-200 到 200)
  }): Poi2 {
    if (config.textOffsetX !== undefined) {
      this.config.textOffsetX = Math.max(
        -200,
        Math.min(200, config.textOffsetX)
      )
    }
    if (config.textOffsetY !== undefined) {
      this.config.textOffsetY = Math.max(
        -200,
        Math.min(200, config.textOffsetY)
      )
    }

    this.createFinalMaterial()
    return this
  }

  /**
   * 接口4: 文字背景控制
   * @param config 背景配置对象
   * @returns 当前POI实例，支持链式调用
   */
  public updateTextBackground(config: {
    enabled?: boolean // 是否显示背景
    opacity?: number // 背景透明度 (0-1)
    color?: string // 背景颜色 (rgb格式)
    shape?: 'circle' | 'rectangle' // 背景形状样式
    size?: number // 背景大小倍数 (0.5-3.0)
  }): Poi2 {
    if (config.enabled !== undefined) {
      if (config.enabled) {
        // 启用背景，使用指定颜色和透明度
        const opacity =
          config.opacity !== undefined
            ? Math.max(0, Math.min(1, config.opacity))
            : 0.8
        const color = config.color || '255, 255, 255'
        this.config.backGroundStyle = `rgba(${color}, ${opacity})`
      } else {
        // 禁用背景
        this.config.backGroundStyle = ''
      }
    } else if (config.opacity !== undefined || config.color !== undefined) {
      // 仅更新透明度或颜色（保持启用状态）
      if (this.config.backGroundStyle) {
        const opacity =
          config.opacity !== undefined
            ? Math.max(0, Math.min(1, config.opacity))
            : 0.8
        const color = config.color || '255, 255, 255'
        this.config.backGroundStyle = `rgba(${color}, ${opacity})`
      }
    }

    // 更新背景形状样式
    if (config.shape !== undefined) {
      this.config.backgroundShape = config.shape
    }

    // 更新背景大小
    if (config.size !== undefined) {
      // 限制大小范围在 0.5 到 3.0 之间
      this.config.backgroundSize = Math.max(0.5, Math.min(3.0, config.size))
    }

    this.createFinalMaterial()
    return this
  }

  /**
   * 接口5: 默认形状控制
   * @param shape 默认形状类型（当图片加载失败时显示）
   * @returns 当前POI实例，支持链式调用
   */
  public updateDefaultShape(
    shape: 'circle' | 'rectangle' | 'triangle' | 'square'
  ): Poi2 {
    this.config.defaultShape = shape
    this.createFinalMaterial()
    return this
  }

  /**
   * 接口6: 形状样式控制
   * @param config 形状样式配置对象
   * @returns 当前POI实例，支持链式调用
   */
  public updateShapeStyle(config: {
    size?: number // 形状大小倍数 (0.5-3.0)
    color?: string // 填充颜色
    strokeColor?: string // 描边颜色
    strokeWidth?: number // 描边宽度 (0-10)
  }): Poi2 {
    // 更新配置 - 像给球员换装备一样! ⚽
    if (config.size !== undefined) {
      this.config.shapeSize = Math.max(0.5, Math.min(100.0, config.size))
    }
    if (config.color !== undefined) {
      this.config.shapeColor = config.color
    }
    if (config.strokeColor !== undefined) {
      this.config.shapeStrokeColor = config.strokeColor
    }
    if (config.strokeWidth !== undefined) {
      this.config.shapeStrokeWidth = Math.max(
        0,
        Math.min(10, config.strokeWidth)
      )
    }

    // 重新渲染
    this.createFinalMaterial()
    return this
  }

  /**
   * 接口7: 形状纹理控制
   * @param textureImage 纹理图片对象或图片URL字符串
   * @returns 当前POI实例，支持链式调用
   */
  public updateShapeTexture(
    textureImage: HTMLImageElement | string | null
  ): Poi2 {
    // 如果传入的是字符串URL，则自动加载图片
    if (typeof textureImage === 'string') {
      // console.log('加载纹理图片:', textureImage)
      const img = new Image()
      img.crossOrigin = 'anonymous'
      img.onload = () => {
        // console.log('纹理图片加载成功:', textureImage)
        this.config.textureImage = img
        this.createFinalMaterial()
      }
      img.onerror = (error) => {
        console.error('纹理图片加载失败:', textureImage, error)
        this.config.textureImage = null
        this.createFinalMaterial()
      }
      img.src = textureImage
    } else {
      // 如果是图片对象或null，直接使用
      this.config.textureImage = textureImage
      // 重新渲染
      this.createFinalMaterial()
      // console.log('形状纹理已更新', textureImage ? '有纹理' : '无纹理')
    }
    return this
  }

  // 旧的内部方法已移除，现在使用公共接口控制

  /**
   * 更新POI参数 - 更简洁的API！
   * @param newConfig 新的配置对象
   * @returns 当前POI实例，支持链式调用
   */
  public updateParams(newConfig: Partial<PoiConfig>): Poi2 {
    // 更新配置
    Object.assign(this.config, newConfig)

    // 处理位置更新
    if (newConfig.position) {
      const pos = newConfig.position.toEPSGWeb()
      this.position.set(pos.x, pos.y, pos.z)
    }

    // 处理图片更新
    if (newConfig.url) {
      this.isImageLoaded = false
      this.loadImageAndUpdate()
      return this
    }

    // 处理纹理图片更新
    if (newConfig.textureImage !== undefined) {
      this.config.textureImage = newConfig.textureImage
    }

    // 重新创建材质
    this.createFinalMaterial()
    return this
  }

  /**
   * 销毁资源
   */
  public dispose(): void {
    if (this.material) {
      const spriteMaterial = this.material as SpriteMaterial
      if (spriteMaterial.map) {
        spriteMaterial.map.dispose()
      }
      spriteMaterial.dispose()
    }

    // 清理纹理图片引用
    this.config.textureImage = null

    // GUI已替换为接口控制，无需清理GUI资源
  }

  // Getter 方法 - 方便外部访问配置
  public get poiName(): string {
    return this.config.name
  }
  public get poiUrl(): string {
    return this.config.url
  }
  public get showText(): boolean {
    return this.config.showText
  }

  /**
   * 获取当前完整配置
   */
  public getCurrentConfig(): Required<PoiConfig> {
    return { ...this.config }
  }

  /**
   * 批量更新多个配置 - 一次性设置多个参数
   * 
   * @example
   * // 一次性更新多个参数
   * poi.batchUpdate({
   *   text: { name: '新名称', size: 20, color: 'blue' },
   *   background: { color: 'rgba(255,255,255,0.8)', shape: 'circle' },
   *   shape: { type: 'triangle', color: 'red' }
   * })
   */
  public batchUpdate(options: {
    text?: {
      name?: string
      size?: number
      color?: string
      isBold?: boolean
      isItalic?: boolean
      strokeColor?: string
      strokeWidth?: number
      font?: string
    },
    position?: any,
    image?: {
      url?: string
      size?: number
    },
    offset?: {
      x?: number
      y?: number
    },
    background?: {
      color?: string
      shape?: 'circle' | 'rectangle'
      size?: number
      opacity?: number
    },
    shape?: {
      type?: 'circle' | 'rectangle' | 'triangle' | 'square'
      color?: string
      strokeColor?: string
      strokeWidth?: number
      size?: number
    },
    layout?: {
      textPosition?: 'top' | 'bottom' | 'left' | 'right' | 'center' | 'image-only' | 'text-only'
      showText?: boolean
      center?: [number, number]
    }
  }): Poi2 {
    const config: Partial<PoiConfig> = {}
    
    // 处理文字相关配置
    if (options.text) {
      if (options.text.name !== undefined) config.name = options.text.name
      if (options.text.size !== undefined) config.size = options.text.size
      if (options.text.color !== undefined) config.textStyle = options.text.color
      if (options.text.isBold !== undefined) config.isBold = options.text.isBold
      if (options.text.isItalic !== undefined) config.isItalic = options.text.isItalic
      if (options.text.strokeColor !== undefined) config.strokeStyle = options.text.strokeColor
      if (options.text.strokeWidth !== undefined) config.strokeWidth = options.text.strokeWidth
      if (options.text.font !== undefined) config.textfont = options.text.font
    }
    
    // 处理位置
    if (options.position !== undefined) config.position = options.position
    
    // 处理图片相关配置 - 使用updateShapeTexture加载图片
    if (options.image) {
      if (options.image.url !== undefined) {
        const img = new Image();
        img.setAttribute('crossOrigin', 'anonymous');
        img.onload = () => this.updateShapeTexture(img);
        img.onerror = () => console.warn('Failed to load shape texture:', options.image.url);
        img.src = options.image.url;
      }
      if (options.image.size !== undefined) config.baseImageSize = options.image.size
    }
    
    // 处理偏移
    if (options.offset) {
      if (options.offset.x !== undefined) config.textOffsetX = options.offset.x
      if (options.offset.y !== undefined) config.textOffsetY = options.offset.y
    }
    
    // 处理背景
    if (options.background) {
      if (options.background.color !== undefined || options.background.opacity !== undefined) {
        const color = options.background.color || '255, 255, 255';
        const opacity = options.background.opacity !== undefined ? Math.max(0, Math.min(1, options.background.opacity)) : 0.8;
        config.backGroundStyle = `rgba(${color}, ${opacity})`;
      }
      if (options.background.shape !== undefined) config.backgroundShape = options.background.shape
      if (options.background.size !== undefined) config.backgroundSize = options.background.size
    }
    
    // 处理形状
    if (options.shape) {
      if (options.shape.type !== undefined) config.defaultShape = options.shape.type
      if (options.shape.color !== undefined) config.shapeColor = options.shape.color
      if (options.shape.strokeColor !== undefined) config.shapeStrokeColor = options.shape.strokeColor
      if (options.shape.strokeWidth !== undefined) config.shapeStrokeWidth = options.shape.strokeWidth
      if (options.shape.size !== undefined) config.shapeSize = options.shape.size
    }
    
    // 处理布局
    if (options.layout) {
      if (options.layout.textPosition !== undefined) config.textPosition = options.layout.textPosition
      if (options.layout.showText !== undefined) config.showText = options.layout.showText
      if (options.layout.center !== undefined) config.center = options.layout.center
    }
    
    // 应用所有配置
    return this.updateParams(config)
  }

  /**
   * 设置POI坠落表面调整
   * @param surface 坠落表面对象
   * @returns 当前POI实例，支持链式调用
   */
  public setFalldown(surface?: Object3D): Poi2 {
    if (surface) {
      this.config.falldownSurface = surface
    }
    
    if (this.config.falldownSurface) {
      let adjustHeightData = {
        mesh: this,
        falldownSurface: this.config.falldownSurface
      }
      this.adjustHeightUtil = new AdjustHeight(adjustHeightData)
      this.adjustHeightUtil.startAdjust()
    }
    return this
  }
}
